import redis
from django.conf import settings
from functools import wraps
import hashlib
import json

class RedisClient:
    _instance = None
    
    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            # 从settings中获取Redis配置
            redis_config = getattr(settings, 'REDIS_CONFIG', {
                'host': 'localhost',
                'port': 6379,
                'db': 0,
                'password': None
            })
            cls._instance.client = redis.Redis(**redis_config)
        return cls._instance

    @classmethod
    def get_client(cls):
        return cls().client

class IdempotencyControl:
    """
    幂等性控制工具类
    """
    
    @staticmethod
    def generate_idempotency_key(request, prefix='idempotency'):
        """
        生成幂等性键
        基于请求路径、方法、用户ID和请求参数生成唯一键
        """
        # 获取请求信息
        path = request.path
        method = request.method
        user_id = request.user.id if hasattr(request, 'user') and request.user.is_authenticated else 'anonymous'
        
        # 获取请求参数
        params = {}
        if method == 'GET':
            params = dict(request.GET)
        elif method == 'POST':
            if request.content_type and 'application/json' in request.content_type:
                try:
                    params = json.loads(request.body.decode())
                except:
                    params = {}
            else:
                params = dict(request.POST)
        
        # 生成唯一键
        key_parts = [
            prefix,
            str(path),
            str(method),
            str(user_id),
            json.dumps(params, sort_keys=True)
        ]
        
        key_string = '|'.join(key_parts)
        return hashlib.md5(key_string.encode()).hexdigest()

    @staticmethod
    def require_idempotency(timeout=60):
        """
        幂等性控制装饰器
        :param timeout: 幂等性控制的超时时间（秒）
        """
        def decorator(func):
            @wraps(func)
            def wrapper(request, *args, **kwargs):
                # 获取幂等性键
                idempotency_key = IdempotencyControl.generate_idempotency_key(request)
                redis_client = RedisClient.get_client()
                
                # 检查是否存在相同的请求
                if redis_client.get(idempotency_key):
                    from common.core.response import ApiResponse
                    from common.constants import ErrorCode
                    return ApiResponse.error(
                        message="重复的请求，请稍后再试",
                        code=ErrorCode.DUPLICATE_REQUEST
                    )
                
                # 设置幂等性标记
                redis_client.setex(idempotency_key, timeout, '1')
                
                try:
                    # 执行原始请求
                    response = func(request, *args, **kwargs)
                    return response
                except Exception as e:
                    # 如果请求失败，删除幂等性标记
                    redis_client.delete(idempotency_key)
                    raise e
                
            return wrapper
        return decorator 